import { Clock } from '../../Source/Cesium.js';
import { FeatureDetection } from '../../Source/Cesium.js';
import { Iso8601 } from '../../Source/Cesium.js';
import { JulianDate } from '../../Source/Cesium.js';
import { Math as CesiumMath } from '../../Source/Cesium.js';
import { VideoSynchronizer } from '../../Source/Cesium.js';
import pollToPromise from '../pollToPromise.js';

describe('Core/VideoSynchronizer', function() {

    //Video textures do not work on Internet Explorer
    if (FeatureDetection.isInternetExplorer()) {
        return;
    }

    function loadVideo() {
        var element = document.createElement('video');
        var source = document.createElement('source');
        source.setAttribute('src', 'Data/Videos/big-buck-bunny-trailer-small.webm');
        source.setAttribute('type', 'video/webm');
        element.appendChild(source);

        source = document.createElement('source');
        source.setAttribute('src', 'Data/Videos/big-buck-bunny-trailer-small.mp4');
        source.setAttribute('type', 'video/mp4');
        element.appendChild(source);

        source = document.createElement('source');
        source.setAttribute('src', 'Data/Videos/big-buck-bunny-trailer-small.mov');
        source.setAttribute('type', 'video/quicktime');
        element.appendChild(source);

        return element;
    }

    it('Can default construct', function() {
        var videoSynchronizer = new VideoSynchronizer();

        expect(videoSynchronizer.clock).not.toBeDefined();
        expect(videoSynchronizer.element).not.toBeDefined();
        expect(videoSynchronizer.epoch).toBe(Iso8601.MINIMUM_VALUE);
        expect(videoSynchronizer.tolerance).toBe(1.0);
        expect(videoSynchronizer.isDestroyed()).toBe(false);
        expect(videoSynchronizer.destroy()).not.toBeDefined();
        expect(videoSynchronizer.isDestroyed()).toBe(true);
    });

    it('Can construct with options', function() {
        var clock = new Clock();
        var element = document.createElement('video');
        var epoch = new JulianDate();
        var tolerance = 0.15;

        var videoSynchronizer = new VideoSynchronizer({
            clock : clock,
            element : element,
            epoch : epoch,
            tolerance: tolerance
        });

        expect(videoSynchronizer.clock).toBe(clock);
        expect(videoSynchronizer.element).toBe(element);
        expect(videoSynchronizer.epoch).toBe(epoch);
        expect(videoSynchronizer.tolerance).toBe(tolerance);
        expect(videoSynchronizer.isDestroyed()).toBe(false);
        expect(videoSynchronizer.destroy()).not.toBeDefined();
        expect(videoSynchronizer.isDestroyed()).toBe(true);
    });

    it('Syncs time when looping', function() {
        var epoch = JulianDate.fromIso8601('2015-11-01T00:00:00Z');
        var clock = new Clock();
        clock.shouldAnimate = false;
        clock.currentTime = epoch.clone();

        var element = loadVideo();
        element.loop = true;

        var videoSynchronizer = new VideoSynchronizer({
            clock : clock,
            element : element,
            epoch : epoch
        });

        return pollToPromise(function() {
            clock.tick();
            return element.currentTime === 0;
        }).then(function() {
            clock.currentTime = JulianDate.addSeconds(epoch, 10, clock.currentTime);
            return pollToPromise(function() {
                clock.tick();
                return element.currentTime === 10;
            });
        }).then(function() {
            clock.currentTime = JulianDate.addSeconds(epoch, 60, clock.currentTime);
            return pollToPromise(function() {
                clock.tick();
                return CesiumMath.equalsEpsilon(element.currentTime, 60 - element.duration, CesiumMath.EPSILON3);
            });
        }).then(function() {
            clock.currentTime = JulianDate.addSeconds(epoch, -1, clock.currentTime);
            return pollToPromise(function() {
                clock.tick();
                return CesiumMath.equalsEpsilon(element.currentTime, element.duration - 1, CesiumMath.EPSILON1);
            });
        }).then(function() {
            videoSynchronizer.destroy();
        });
    });

    it('Syncs time when not looping', function() {
        var epoch = JulianDate.fromIso8601('2015-11-01T00:00:00Z');
        var clock = new Clock();
        clock.shouldAnimate = false;
        clock.currentTime = epoch.clone();

        var element = loadVideo();

        var videoSynchronizer = new VideoSynchronizer({
            clock : clock,
            element : element,
            epoch : epoch
        });

        return pollToPromise(function() {
            clock.tick();
            return element.currentTime === 0;
        }).then(function() {
            clock.currentTime = JulianDate.addSeconds(epoch, 10, clock.currentTime);
            return pollToPromise(function() {
                clock.tick();
                return element.currentTime === 10;
            });
        }).then(function() {
            clock.currentTime = JulianDate.addSeconds(epoch, 60, clock.currentTime);
            return pollToPromise(function() {
                clock.tick();
                return CesiumMath.equalsEpsilon(element.currentTime, element.duration, CesiumMath.EPSILON3);
            });
        }).then(function() {
            clock.currentTime = JulianDate.addSeconds(epoch, -1, clock.currentTime);
            return pollToPromise(function() {
                clock.tick();
                return element.currentTime === 0;
            });
        }).then(function() {
            videoSynchronizer.destroy();
        });
    });

    it('Plays/pauses video based on clock', function() {
        var epoch = JulianDate.fromIso8601('2015-11-01T00:00:00Z');
        var clock = new Clock();

        // Since Chrome doesn't allow video playback without user
        // interaction, we use a mock element.
        var element = jasmine.createSpyObj('MockVideoElement', ['addEventListener', 'removeEventListener', 'play', 'pause']);
        element.paused = false;
        element.play.and.callFake(function() {
            this.paused = false;
        });
        element.pause.and.callFake(function() {
            this.paused = true;
        });

        var videoSynchronizer = new VideoSynchronizer({
            clock : clock,
            element : element,
            epoch : epoch
        });

        clock.shouldAnimate = false;
        clock.tick();
        expect(element.pause.calls.count()).toEqual(1);

        clock.shouldAnimate = true;
        clock.tick();
        expect(element.play.calls.count()).toEqual(1);

        clock.shouldAnimate = false;
        clock.tick();
        expect(element.pause.calls.count()).toEqual(2);

        videoSynchronizer.destroy();
    });
});
